/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package th.manager;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.oas.thit._this.flight.xsd.InfoSmsRequestBody;
import com.oas.thit.xmlmessage.xsd.Header;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import javax.xml.bind.JAXBElement;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static th.manager.SequenceManager.intToString;
import th.model.InfoPetugas;
import th.model.KodStatusSms;
import th.model.SeqNum;
import th.model.Sms;
import th.stripes.Configuration;
import th.stripes.util.FTPUtil;

/**
 *
 * @author fikri
 */
public class SMSBulkManager {

    @Inject
    Provider<SessionFactory> sp;
    private static Logger LOG = LoggerFactory.getLogger(SMSBulkManager.class);
    private static final int TIMEOUT = 30 * 60 * 1000;
    private static String URL = "https://www.etracker.cc/mes/mesbulk.aspx";
    //private static String URL = "https://202.9.104.124/mes/mesbulk.aspx";
    private static String HTTP_USER = "lthbulk";
    private static String HTTP_PASS = "lthbulk9001";
    private static String SUCCESSFUL = "0000";
    private static String SMS_ENQ_MSG_ID = "TPSMSDATWD01";
    private static String HEADER_ID_SMS_ENQUIRY = "TPSMSDATWD01";
    private static String REMOTE_USER = "Administrator";
    private static String REMOTE_PASS = "P@ssw0rd";
    private static String BLAST_TAG = "0";
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    private static ArrayList<String> LIST_OF_KT = new ArrayList<String>();
    @Inject
    Configuration conf;

    /**
     * Generate list of jemaah in text file
     *
     * @param date
     * @return
     */
    public boolean getListOfJemaah(String date) {
        boolean FLAG_RTN = false;

        String responseCode = "";

        try { // Call Web Service Operation
            com.oas.thit._this.services.THISServices service = new com.oas.thit._this.services.THISServices();
            com.oas.thit._this.services.THISServicesPortType port = service.getTHISServicesHttpSoap11Endpoint();
            LOG.info("port {}", port.toString());
            // TODO initialize WS operation arguments here
            com.oas.thit._this.flight.xsd.InfoSmsRequest req = new com.oas.thit._this.flight.xsd.InfoSmsRequest();

            com.oas.thit._this.flight.xsd.ObjectFactory objFactory = new com.oas.thit._this.flight.xsd.ObjectFactory();
            req.setHeader(createHeader(SMS_ENQ_MSG_ID, HEADER_ID_SMS_ENQUIRY));

            InfoSmsRequestBody reqBody = objFactory.createInfoSmsRequestBody();
            reqBody.setTHFlightDate(objFactory.createInfoSmsRequestBodyTHFlightDate(date)); //20120920
            reqBody.setTHFlightNo(objFactory.createInfoSmsRequestBodyTHFlightNo("")); //kt20

            JAXBElement<InfoSmsRequestBody> jReqBody = objFactory.createInfoSmsRequestBody(reqBody);
            req.setBody(jReqBody);

            // TODO process result here
            com.oas.thit._this.flight.xsd.InfoSmsResponse result = port.hajjflightinfoSMS(req);

            Header header = result.getHeader().getValue();
            responseCode = header.getResponseCode().getValue();
            LOG.debug("responseCode {} ", responseCode);
            if (responseCode.equals(SUCCESSFUL)) {
                FLAG_RTN = true;
            } else {
                FLAG_RTN = false;
            }

        } catch (Exception ex) {
            LOG.error("error occured {} !!", ex.getCause().getMessage());
        }

        return FLAG_RTN;
    }

    /**
     * read and send SMS Jemaah
     */
    public void startSmsProcess() {

        String sms_dir = conf.getProperty("sms.dir");
        String sms_arc_dir = conf.getProperty("sms.arc.dir");
        String remote_sms_addr = conf.getProperty("sms.remote.addr");
        String remote_sms_incoming_dir = conf.getProperty("sms.remote.incoming.dir");
        String remote_sms_arc_dir = conf.getProperty("sms.remote.arc.dir");
        //doFTPfile(remote_sms_dir, remote_sms_incoming_dir, sms_dir, remote_sms_arc_dir);

        File[] files = readDir(sms_dir);

        LOG.debug("BLAST_TAG (startSMSProcess()) = " + BLAST_TAG);

        if (files != null && files.length > 0) {
            readAndSendSMS(files);
            moveAndDeleteFile(files, sms_arc_dir);

//            if (BLAST_TAG.equals("1")) {
//                LOG.debug("execute : sms (Petugas Haji) process starting !!");
//                startSmsNotification();
//                LOG.debug("execute : sms process finished !!");
//                BLAST_TAG = "0";
//            }

        }

    }

    /**
     * Send SMS Notification to PK Jab Haji, Ketua Unit, THCC Group
     */
    public void startSmsNotification() {

        String sms_dir = conf.getProperty("sms.dir.petugas");
        File[] files = readDir(sms_dir);
        if (files != null && files.length > 0) {
            readAndSendSMSNotication(files);
            // moveAndDeleteFile(files, sms_arc_dir);
        }

    }

    private void readAndSendSMSNotication(File[] files) {
        LOG.info("readAndSendSMSNotification");

        String msg = "";
        int i = 0;
        //bace listOfKT
        for (int j = 0; j < LIST_OF_KT.size(); j++) {

            String listKt = LIST_OF_KT.get(j).toString();

            String[] listKtSplit = listKt.split("\\$\\$");

            LOG.info("LIST_OF_KT[1] : laporDt {}", listKtSplit[0]);
            LOG.info("LIST_OF_KT[1] : lapotTpt {}", listKtSplit[1]);
            LOG.info("LIST_OF_KT[1] : laporTime {}", listKtSplit[2]);
            LOG.info("LIST_OF_KT[1] : laporWaktu {}", listKtSplit[3]);
            LOG.info("LIST_OF_KT[1] : kt {}", listKtSplit[4]);

            String laporDt = listKtSplit[0].toString();
            String lapotTpt = listKtSplit[1].toString();
            String laporTime = listKtSplit[2].toString();
            String laporWaktu = listKtSplit[3].toString();
            String kt = listKtSplit[4].toString();

            // for (File file : files) {  
            for (i = 0; i < files.length; i++) {
                try {
                    // Scanner scan = new Scanner(file).useDelimiter("\n");
                    LOG.info("Jemaah ke : ", i);
                    Scanner scan = new Scanner(files[i]).useDelimiter("\n");
                    while (scan.hasNext()) {
                        String content = scan.next();
                        if (StringUtils.isBlank(content)) {
                            continue;
                        }
                        LOG.info("content {}", content);
                        String[] f = content.split("\\$\\$");

                        LOG.info("f[1] : No Tel {}", f[1]);

                        String noTel = f[1].toString();

<<<<<<< .mine
                        msg = String.format("INFO HAJI(ADMIN): Tn/Pn dikehendaki lapor diri %s di %s pada %s jam %s%s. "
                                + "Jika ada sebarang pertanyaan, sila hubungi 03-62071919.", kt, lapotTpt, laporDt, laporTime, laporWaktu);
=======
                        msg = String.format("INFO HAJI(PETUGAS): Tn/Pn dikehendaki lapor diri %s di %s pada %s jam %s%s. "
                                + "Sebarang pertanyaan sila hubungi 03-62071919.", kt, lapotTpt, laporDt, laporTime, laporWaktu);
>>>>>>> .r689

                        // msg = String.format("INFO HAJI: SMS peringatan lapor diri telah dihantar kepada jemaah.");

                        blastSMS(noTel, msg);
                    }
                } catch (FileNotFoundException ex) {
                    //TODO : create report for file not found !!
                }
            }
            LOG.info("Jumlah Jemaah : ", i);
        }
        System.gc();
    }

    private void doFTPfile(String REMOTE_ADDR, String REMOTE_INC_DIR, String LOCAL_DIR, String REMOTE_ARC_DIR) {
        FTPUtil ftp = new FTPUtil();
        ftp.downloadAndRemove(REMOTE_USER, REMOTE_PASS, REMOTE_ADDR, REMOTE_INC_DIR, LOCAL_DIR, REMOTE_ARC_DIR);
    }

    private File[] readDir(String INCOMING_DIR) {
        File file = new File(INCOMING_DIR);
        if (!file.exists()) {
            LOG.debug("dir {} not exist", INCOMING_DIR);
            return null;
        }
        File[] files = null;
        if (file.isDirectory()) {
            files = file.listFiles();
        }
        return files;
    }

    /**
     *
     * Read file for todays date only and send SMS.
     *
     * @param files
     */
    private void readAndSendSMS(File[] files) {
        LOG.info("readAnsSendSMS");

        List<String> listOfKT = new ArrayList<String>();

        String currentDate = getCurrentDate();

        StringBuilder msg = new StringBuilder("INFO HAJI: Tn/Pn dikehendaki lapor diri %s di %s pada %s jam %s%s. ")

                .append("Jika ada sebarang pertanyaan, sila hubungi 03-62071919.");


        StringBuilder msg_petugas = new StringBuilder("INFO HAJI(ADMIN): Tn/Pn dikehendaki lapor diri %s di %s pada %s jam %s%s. ")
                .append("Jika ada sebarang pertanyaan, sila hubungi 03-62071919.");


        /**
         * Format of file name : 20130829__SMS.txt
         */
        String nameOfFile = currentDate + "__SMS.txt";

        // File fileNew = new File(files);

        // for (File file : files) {     
        for (int i = 0; i < files.length; i++) {
            try {

                String fileName = files[i].getName().toString();

                Map<String, Map<String, String>> parent = new HashMap<String, Map<String, String>>();

                Map<String, String> child = new HashMap<String, String>();
                int count = 0;
                int record = 0;

                if (fileName.equals(nameOfFile)) {
                    Scanner scan = new Scanner(files[i]).useDelimiter("\n");
                    //Scanner scan = new Scanner(fileToRead).useDelimiter("\n");                    
                    while (scan.hasNext()) {
                        String content = scan.next();
                        if (StringUtils.isBlank(content)) {
                            continue;
                        }
                        LOG.info("content {}", content);
                        String[] f = content.split("\\$\\$");


                        LOG.info("f[3] {}", f[3]);
                        LOG.info("f[7] {}", f[7]);
                        LOG.info("f[8] {}", f[8]);
                        LOG.info("f[9] {}", f[9]);
                        LOG.info("f[10] {}", f[10]);

                        String currKT = f[0].toString();
                        String noTel = f[3].toString();
                        String laporDt = f[7].toString();
                        String lapotTpt = f[8].toString();
                        String laporTime = f[9].toString();
                        String laporWaktu = f[10].toString();                        

                        //pecah kepada 10 rekod utk sekali penghantaran
                        if (ArrayUtils.contains(listOfKT.toArray(), currKT)) {
                            Map<String, String> m = parent.get(currKT);
                            if (m != null) {
                                if (count > 10) {
                                    count = 1;
                                    record++;
                                    parent.get(currKT).put("phones" + record, noTel);

                                } else {
                                    StringBuilder noPhone = new StringBuilder(m.get("phones" + record));
                                    if (noPhone.length() > 0) {
                                        noPhone.append(",");
                                    }
                                    noPhone.append(noTel);
                                    parent.get(currKT).put("phones" + record, noPhone.toString());
                                }
                                count++;
                            }
                        } else {
                            count = 2;
                            record = 0;
                            child = new HashMap<String, String>();
                            child.put("phones" + record, noTel);
                            child.put("msg", String.format(msg.toString(), currKT, lapotTpt, laporDt, laporTime, laporWaktu));
                            child.put("msg_petugas", String.format(msg_petugas.toString(), currKT, lapotTpt, laporDt, laporTime, laporWaktu));
                            parent.put(currKT, child);
                            listOfKT.add(currKT);
                        }
                    }
                }

                if (parent.size() > 0) {
                    for (Map.Entry<String, Map<String, String>> m : parent.entrySet()) {
                        Map<String, String> value = m.getValue();
                        if (value != null) {
                            String content = value.get("msg");
                            for (int a=0; a<50;a++) {
                                String phonesNo = value.get("phones" + a);
                                if (StringUtils.isBlank(phonesNo)) break;
                                LOG.info("phonesNo {}", phonesNo);
                                if (StringUtils.isNotBlank(phonesNo)) {
                                    blastSMS(phonesNo, content);
                            }                            
                            }                            
                            String contentPetugas = value.get("msg_petugas");
                            String phonesPetugas = getInfoPetugas();
                            if ( StringUtils.isNotBlank( phonesPetugas )) {
                                blastSMS(phonesPetugas, contentPetugas);
                            }
                        }
                    }
                }

            } catch (FileNotFoundException ex) {
                LOG.error("ex{}", ex);
            }
        }

        System.gc();
    }

    /**
     * Move and delete file of todays date
     *
     * @param files
     * @param ARCHIVE_DIR
     */
    private void moveAndDeleteFile(File[] files, String ARCHIVE_DIR) {
        LOG.info("moveAndDeleteFile");

        String currentDate = getCurrentDate();
        String nameOfFile = currentDate + "__SMS.txt";

        File archiveDir = new File(ARCHIVE_DIR);
        if (!archiveDir.exists()) {
            archiveDir.mkdirs();
        }

        // for (File file : files) {  
        for (int i = 0; i < files.length; i++) {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try {

                String fileName = files[i].getName().toString();

                if (fileName.equals(nameOfFile)) {

                    File movedFile = new File(ARCHIVE_DIR + (ARCHIVE_DIR.endsWith(File.separator) ? "" : File.separator) + files[i].getName());
                    fis = new FileInputStream(files[i]);
                    fos = new FileOutputStream(movedFile);
                    copyStream(fis, fos);

                    files[i].delete();
                }
            } catch (FileNotFoundException ex) {
                LOG.error("FileNotFoundException : {}", ex.getMessage());
            } catch (IOException ioe) {
                LOG.error("IOException : {}", ioe.getMessage());
            } finally {
                try {
                    if (fis != null) {
                        fis.close();
                    }
                    if (fos != null) {
                        fos.close();
                    }
                } catch (Exception ex) {
                }
            }
        }


//        for (File file : files) {
//            file.delete();
//        }
    }

    public void sendBulkSMS(List<Map<String, String>> listOfJemaah) {

        StringBuilder listOfPhoneNos = new StringBuilder();

        if (!listOfJemaah.isEmpty()) {
            for (Map<String, String> map : listOfJemaah) {
                String phoneNo = map.get("phoneNo");
                if (listOfPhoneNos.length() > 0) {
                    listOfPhoneNos.append(",");
                }
                listOfPhoneNos.append(phoneNo);
            }

            String msg = String.format("Tn/Pn dikehendaki lapor diri di Kompleks Tabung Haji pada %s jam %s. "
                    + "Sebarang pertanyaan sila hubungi 03-62071919", "dd/mm/yyyy", "hh:mm sss");

            blastSMS(listOfPhoneNos.toString(), "");
        }
    }

    private void blastSMS(String phoneNo, String message) {
        StatelessSession ss = null;
        Transaction tx = null;

        try {

            StringBuilder cmd = new StringBuilder(URL)
                    .append("?user=")
                    .append(HTTP_USER)
                    .append("&pass=")
                    .append(HTTP_PASS)
                    .append("&type=0&to=")
                    .append(phoneNo)
                    .append("&from=LTH&text=")
                    .append(URLEncoder.encode(message, "UTF-8"))
                    .append("&servid=MES01");

            LOG.info("cmd :{}", cmd.toString());


            HttpClient client = new HttpClient();
            GetMethod method = new GetMethod(cmd.toString());
            method.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, TIMEOUT);
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(3, false));

            int statusCode = client.executeMethod(method);
            BufferedReader rd = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
            String line = "";
            ss = sp.get().openStatelessSession();
            tx = ss.beginTransaction();

            while ((line = rd.readLine()) != null) {
                LOG.info("line {}", line);
                String[] results = line.split("\\|");
                for (String result : results) {
                    String[] res = result.split(",");
                    if (res.length > 0) {
                        String phone = StringUtils.isBlank(res[0]) ? "" : res[0].trim();
                        String msisdn = StringUtils.isBlank(res[1]) ? "" : res[1].trim();
                        String sts = StringUtils.isBlank(res[2]) ? "" : res[2].trim();
                        if (StringUtils.isNotBlank(phone) && StringUtils.isNotBlank(sts)) {
                            Sms sms = new Sms();
                            sms.setNoTel(phone);
                            sms.setNoAkaun(sts);
//                            Criteria query = ss.createCriteria(KodStatusSms.class)
//                                    .add(Restrictions.eq("kod", sts));
//                            
//                            KodStatusSms kod = (KodStatusSms) query.uniqueResult();                            
//                            sms.setKodStsSms(kod);
                            sms.setMsisdn(msisdn);
                            sms.setTarikhHantar(new Date());
                            ss.insert(sms);
                        }
                    }
                }

                BLAST_TAG = "1";

            }
            tx.commit();
            LOG.info("status {}", statusCode);
            LOG.info("BLAST_TAG (BlastSMS())", BLAST_TAG);


        } catch (Exception ex) {
            LOG.error("error : {} ", ex);
            if (tx != null) {
                tx.rollback();
            }
        } finally {
            if (ss != null) {
                ss.close();
            }
        }
    }

    public static void copyStream(InputStream in, OutputStream out) throws IOException {
        final int MAX = 4096;
        byte[] buf = new byte[MAX];
        for (int bytesRead = in.read(buf, 0, MAX);
                bytesRead != -1;
                bytesRead = in.read(buf, 0, MAX)) {
            out.write(buf, 0, bytesRead);
        }
    }

    private String getHeaderID(String msgID, String headerID) {
        String date = sdf.format(new Date());
        String seq = getSequence(msgID);
        SeqNum seqNum = new SeqNum();
        seqNum.setNum(Integer.parseInt(seq));
        seqNum.setUrusan(msgID);
        updateSequence(seqNum);
        return headerID + date + seq;
    }

    private JAXBElement<Header> createHeader(String msgID, String headerID) {

        com.oas.thit.xmlmessage.xsd.ObjectFactory objHeader = new com.oas.thit.xmlmessage.xsd.ObjectFactory();
        Header reqHead = objHeader.createHeader();
        reqHead.setMsgId(objHeader.createHeaderMsgId(msgID));
        reqHead.setResponseCode(objHeader.createHeaderResponseCode("0000"));
        String txId = getHeaderID(msgID, headerID);
        reqHead.setTxid(objHeader.createHeaderTxid(txId));
        return objHeader.createEventHeader(reqHead);
    }

    private String getSequence(String msgId) {
        StatelessSession ss = null;

        try {
            ss = sp.get().openStatelessSession();

            Criteria query = ss.createCriteria(SeqNum.class)
                    .add(Restrictions.eq("urusan", msgId));

            SeqNum sequnce = (SeqNum) query.uniqueResult();

            int seq = sequnce.getNum() + 1;
            return intToString(seq, 4);
        } catch (HibernateException ex) {
            LOG.error(null, ex);
        } finally {
            if (ss != null) {
                ss.close();
            }
        }
        return "";
    }

    private String getInfoPetugas() {
        StatelessSession ss = null;

        StringBuilder sb = new StringBuilder();

        try {
            ss = sp.get().openStatelessSession();

            Criteria query = ss.createCriteria(InfoPetugas.class);

            List<InfoPetugas> info = query.list();
            if (!info.isEmpty()) {
                for (InfoPetugas petugas : info) {
                    if (petugas != null && StringUtils.isNotBlank(petugas.getNoTel())) {
                        if (sb.length() > 0) {
                            sb.append(",");
                        }
                        sb.append(petugas.getNoTel());
                    }
                }
            }

        } catch (HibernateException ex) {
            LOG.error(null, ex);
        } finally {
            if (ss != null) {
                ss.close();
            }
        }
        return sb.toString();
    }

    private void updateSequence(SeqNum seq) {
        Session ss = null;
        Transaction tx = null;
        try {
            ss = sp.get().openSession();
            tx = ss.beginTransaction();
            Criteria query = ss.createCriteria(SeqNum.class)
                    .add(Restrictions.eq("urusan", seq.getUrusan()));
            SeqNum seqNum = (SeqNum) query.uniqueResult();
            seqNum.setNum(seq.getNum());
            ss.update(seqNum);
            tx.commit();
        } catch (HibernateException ex) {
            tx.rollback();
            LOG.error(null, ex);
        } finally {
            if (ss != null) {
                ss.close();
            }
        }
    }
    
    public void sendSmsManual(File[] files) {
        readAndSendSMS(files);
    }

    public static void main(String[] args) {        
    }

    public String getCurrentDate() {

        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        Date date = new Date();
        String currentDate = dateFormat.format(date);
        System.out.println(currentDate);
        return currentDate;
    }
}
